using System; 
using System.Collections.Generic; 
using System.IO;
using System.Text; 
using System.Threading.Tasks; 
using Newtonsoft.Json; 
using UnityEngine;
using XFABManager; 


namespace XFGameFramework.ArchiveSystem
{ 
    /// <summary>
    /// 存档系统业务逻辑
    /// </summary>
    public class ArchiveManager 
    {

        #region 常量

        /// <summary>
        /// 加密Key的默认值
        /// </summary>
        private static string EncryptKey = string.Empty;
        
        /// <summary>
        /// 后缀
        /// </summary>
        private static string Suffix = "sav";

        #endregion

        #region 字段

        private static Dictionary<int, IArchiveModel> models = new Dictionary<int, IArchiveModel>();

        private static List<int> ids = null;

        private static int currentUseID = 0;


        #endregion

        #region 属性

        /// <summary>
        /// 所有的ID
        /// </summary>
        public static List<int> AllIds
        {
            get
            {
                if (ids == null)
                {
                    ids = new List<int>();
                     
                    if (!File.Exists(ListPath))
                        File.WriteAllText(ListPath, string.Empty); // 创建文件

                    string all_id_str = File.ReadAllText(ListPath);

                    if (!string.IsNullOrEmpty(all_id_str))
                    {
                        try
                        {
                            List<int> all_ids = JsonConvert.DeserializeObject<List<int>>(all_id_str);
                            ids.AddRange(all_ids);
                        }
                        catch (Exception)
                        {
                        }
                    }
                }

                return ids;
            }
        }

        /// <summary>
        /// 当前使用的ID
        /// </summary>
        public static int CurrentUseId
        {
            get
            {
                return currentUseID;
            }
            set
            {
                currentUseID = value; 
                File.WriteAllText(CurrentPath, currentUseID.ToString());
            } 
        }

        /// <summary>
        /// 存档文件的目录
        /// </summary>
        public static string SavesDir
        {
            get
            {
                string p = null;

#if UNITY_EDITOR
                p = string.Format("{0}/../Library/ArchiveDirectory/", Application.dataPath);
#else
                p = XFABTools.DataPath("ArchiveDirectory");
                string platform = XFABTools.GetCurrentPlatformName();
                if (p.EndsWith(platform))
                    p = p.Substring(0, p.Length - platform.Length);
                
#endif
                if (!Directory.Exists(p))
                    Directory.CreateDirectory(p);
                
                return p;
            }
        }
        
        private static string CurrentPath 
        {
            get 
            { 
                if (SavesDir.EndsWith("/")) 
                    return string.Format("{0}current.{1}", SavesDir,Suffix);
                
                return string.Format("{0}/current.{1}", SavesDir,Suffix);
            }
        }

        private static string ListPath
        {
            get
            {
                if (SavesDir.EndsWith("/"))
                    return string.Format("{0}list.{1}", SavesDir, Suffix);

                return string.Format("{0}/list.{1}", SavesDir, Suffix);
            }
        }

        #endregion
         
        #region 方法

        //[RuntimeInitializeOnLoadMethod]
        //private static void Init()
        //{
        //    models.Clear();
        //    ids = null;
        //}


        static ArchiveManager() 
        {
            currentUseID = 1;

            if (File.Exists(CurrentPath))
            {
                string content = File.ReadAllText(CurrentPath);
                int.TryParse(content, out currentUseID);
            }
        }

        /// <summary>
        /// 设置存档文件的加密key
        /// </summary>
        /// <param name="key">密钥</param>
        public static void SetEncryptKey(string key) {
            if (string.IsNullOrEmpty(key))
                return;
            EncryptKey = key;
        }

        /// <summary>
        /// 获取存档文件的加密key
        /// </summary>
        /// <returns></returns>
        public static string GetEncryptKey() {
            return EncryptKey;
        }

        /// <summary>
        /// 创建存档
        /// </summary>
        public static T Create<T>(int id) where T : class, IArchiveModel, new()
        {
            T archiveModel = new T();
            archiveModel.Id = id;
            models.Add(archiveModel.Id, archiveModel);
            // 保本到本地
            string path = GetArchivePath(id);

            string content = JsonConvert.SerializeObject(archiveModel);

            // 如果密钥不为空 则加密一下
            if (!string.IsNullOrEmpty(EncryptKey))
                content = EncryptTools.Encrypt(content, EncryptKey);

            File.WriteAllText(path, content);

            if (!AllIds.Contains(id))
            {
                AllIds.Add(id);
                RefreshAllID();
            }
            return archiveModel;
        }

        /// <summary>
        /// 异步创建存档
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="id"></param>
        /// <returns></returns>
        public static Task<T> CreateAsync<T>(int id) where T : class, IArchiveModel, new() 
        {
            return Task.Run(() => { return Create<T>(id); });
        }

        /// <summary>
        /// 删除存档
        /// </summary>
        /// <param name="id"></param>
        public static void Delete(int id)
        {
            if(models.ContainsKey(id))
                models.Remove(id);
            // 删除本地内容
            string path = GetArchivePath(id);
           
            if(File.Exists(path))
                File.Delete(path);

            if (AllIds.Contains(id)) 
            { 
                AllIds.Remove(id);
                RefreshAllID();
            }

        }

        /// <summary>
        /// 异步删除
        /// </summary>
        /// <param name="id"></param>
        public static Task DeleteAsync(int id) {
            return Task.Run(() => Delete(id));
        }

        /// <summary>
        /// 保存存档(写入存档文件)
        /// </summary>
        /// <param name="id"></param>
        public static void Save(int id)
        {
            if (!models.ContainsKey(id)) 
                return;

            IArchiveModel model = models[id];
            if (model == null) return;
            // 保存到本地
            string path = GetArchivePath(id);
 
            string content = JsonConvert.SerializeObject(model, Formatting.Indented);

            // 如果密钥不为空 则加密一下
            if(!string.IsNullOrEmpty(EncryptKey))
                content = EncryptTools.Encrypt(content, EncryptKey);

            File.WriteAllText(path, content); 
        }

        /// <summary>
        /// 异步保存
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        public static Task SaveAsync(int id) 
        {
            return Task.Run(()=>Save(id));
        }

        /// <summary>
        /// 查询存档
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="id"></param>
        /// <returns></returns>
        public static T Get<T>(int id) where T : class ,IArchiveModel ,new()
        {
            T model = null;

            if(models.ContainsKey(id))
                model = models[id] as T;

            if (model != null) 
                return model;

            string path = GetArchivePath(id);

            if(!File.Exists(path)) 
                return null;

            try
            {
                string content = File.ReadAllText(path);

                if(!string.IsNullOrEmpty(EncryptKey))
                    content = EncryptTools.Decrypt(content, EncryptKey);

                model = JsonConvert.DeserializeObject<T>(content);
                model.Id = id;
                models.Add(id, model);
            }
            catch (Exception)
            {
            }
             
            return model;
        }

        /// <summary>
        /// 查询当前正在使用的存档
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <returns></returns>
        public static T Get<T>() where T : class, IArchiveModel, new()
        {
            return Get<T>(CurrentUseId);
        }

        /// <summary>
        /// 异步查询存档(从存档文件读取)
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="id"></param>
        /// <returns></returns>
        public static async Task<T> GetAsync<T>(int id) where T : class, IArchiveModel, new()
        {
            T model = null;

            if (models.ContainsKey(id))
                model = models[id] as T;

            if (model != null)
                return model;
            
            string path = GetArchivePath(id);

            if (!File.Exists(path))
                return null;

            try
            {
                using FileStream stream = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.Read, 4096, FileOptions.Asynchronous | FileOptions.SequentialScan);

                //using FileStream stream = File.OpenRead(path);

                byte[] bytes = new byte[stream.Length];

                await stream.ReadAsync(bytes, 0, bytes.Length);

                string content = Encoding.UTF8.GetString(bytes);

                if (!string.IsNullOrEmpty(EncryptKey))
                    content = EncryptTools.Decrypt(content, EncryptKey);

                model = JsonConvert.DeserializeObject<T>(content);
                model.Id = id;
                models.Add(id, model);
            }
            catch (Exception)
            {
            }
             
            return model;
        }

        /// <summary>
        /// 异步查询当前正在使用的存档
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <returns></returns>
        public static Task<T> GetAsync<T>() where T : class, IArchiveModel, new()
        {
            return GetAsync<T>(CurrentUseId);
        }

        /// <summary>
        /// 获取某个存档文件路径
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        public static string GetArchivePath(int id)
        {
            return string.Format("{0}ArchiveModel{1}.{2}", SavesDir, id,Suffix);
        }
         
        private static void RefreshAllID() 
        {
            string json = JsonConvert.SerializeObject(AllIds);
            File.WriteAllText(ListPath, json); 
        }

        /// <summary>
        /// 异步加载所有存档
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <returns></returns>
        public static async Task LoadAllAsync<T>() where T : class, IArchiveModel, new()
        {
            foreach (var id in AllIds)
            {
                await GetAsync<T>(id);
            }
        }

        #endregion

    }

}